using System;
using System.ComponentModel.Composition;
using System.Windows;
using Microsoft.Win32;
using Red.Core;
using Red.Controls.Shell;
using Red.EngineData.Protocol.Interop;
using Red.Controls;
using Red.Controls.ViewModels;
using System.ComponentModel;
using System.Xml;
using System.Collections.Generic;

namespace Red.Toolkit.PhysicalDecorationEditor
{
    /// <summary>
    ///     This is how we make the editor a plug-in
    /// </summary>
    [Export( typeof( IEditorInfo ) )]
    public class EditorInfo : IEditorInfo
    {
        public string Name
        {
            get { return "Physical Decoration Editor"; }
        }

        public Type WindowClass
        {
            get { return typeof( PhysicalDecorationEditor ); }
        }

        public Type SettingsClass
        {
            get { return typeof( UserSettings ); }
        }
    }

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class PhysicalDecorationEditor : RedEditorWindow, INotifyPropertyChanged
    {
        #region Data 

        bool _isSimulationRunning = false;
        bool _isSimulationPaused = false;

        Dictionary<String, PhysicsObjectCreationInfo> _objectCreationInfos;

        #endregion

        #region Properties

        public bool IsSimulationRunning
        {
            get { return _isSimulationRunning; }
            set
            {
                if (_isSimulationRunning != value)
                {
                    _isSimulationRunning = value;
                    FirePropertyChanged("IsSimulationRunning");
                }
            }
        }
        public bool IsSimulationPaused
        {
            get { return _isSimulationPaused; }
            set
            {
                if (_isSimulationPaused != value)
                {
                    _isSimulationPaused = value;
                    FirePropertyChanged("IsSimulationPaused");
                }
            }
        }

        #endregion

        #region Events

        private void FirePropertyChanged(string propName)
        {
            if (PropertyChanged != null)
            {

                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion


        public PhysicalDecorationEditor( IEditorHost host, EditorInstanceData instanceData, EditorSharedData sharedData )
            : base( host, instanceData, sharedData )
        {
            FillShapesPallete();
            InitializeComponent();

            BackendInitialized += RedMainWindow_BackendInitialized;
        }

        private void RedMainWindow_BackendInitialized( object sender, EventArgs e )
        {
            _structureView.Initialize( InstanceData.RootEditorItem.Data );

        }

        private async void LoadBufferBtn_Click( object sender, RoutedEventArgs e )
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            if ( openFileDialog.ShowDialog() == true )
            {
                String filePath = openFileDialog.FileName;
                var res = await InstanceData.RootEditorItem.ExecuteAsync<bool>( "loadPhysXBuffer", filePath );
                if ( res.Value )
                {
                    _structureView.RequestRootSync();
                }
                else
                {
                    await ShowErrorAsync( res.Message );
                }
            }
        }

        private async void StartSimulation_Click(object sender, RoutedEventArgs e)
        {
            await InstanceData.RootEditorItem.SetSubValueAsync<String>("preview.editMode", "Simulation");
            IsSimulationRunning = true;

            // temp?
            DataItem preview = await InstanceData.RootEditorItem.DigUpSubItemAsync("preview");
            await InstanceData.RootEditorItem.RebuildAsync();
        }

        private async void StopSimulation_Click(object sender, RoutedEventArgs e)
        {
            IsSimulationRunning = false;
            await InstanceData.RootEditorItem.SetSubValueAsync<String>("preview.editMode", "Default");

            // temp?
            DataItem preview = await InstanceData.RootEditorItem.DigUpSubItemAsync("preview");
            await InstanceData.RootEditorItem.RebuildAsync();

        }

        private async void PauseSimulation_Click(object sender, RoutedEventArgs e)
        {
            DataItem isPaused = await InstanceData.RootEditorItem.DigUpSubItemAsync("preview.simulation.isPaused");
            await isPaused.RebuildAsync();
            isPaused.Value = "true";
            IsSimulationPaused = true;
        }

        private async void ResumeSimulation_Click(object sender, RoutedEventArgs e)
        {
            DataItem isPaused = await InstanceData.RootEditorItem.DigUpSubItemAsync("preview.simulation.isPaused");
            await isPaused.RebuildAsync();
            isPaused.Value = "false";
            IsSimulationPaused = false;
        }

        private async void RedEditorWindow_OnDataIntercepted(object sender, DataInterceptionEventArgs e)
        {
           String key = e.Data.GetData("RTTIValueHolder") as String;

           PhysicsObjectCreationInfo objectInfo = _objectCreationInfos[key];

           // fill from interface, temp for now
           objectInfo.MaterialName = "default";

           // fill from interface, temp for now
           objectInfo.CollisionGroupName = "RigidBody";

           DataItem selectedObject = await InstanceData.RootEditorItem.DigUpSubItemAsync("preview.selection");
           await selectedObject.RebuildAsync();

           if ( selectedObject.Children.Count > 0 )
           {
               DataItem typeDI = await selectedObject.DigUpSubItemAsync("baseType");

               EPhysicsBaseType baseType = EPhysicsBaseType.EPBT_Base;
               if (EnumExtensions.FromString(out baseType, typeDI.Value))
               {
                   if (baseType == EPhysicsBaseType.EPBT_Actor) // actor is selected
                   {
                       DataItem idDI = await selectedObject.DigUpSubItemAsync("physicsBaseId");
                       Int64 baseId = -1;

                       if (Int64.TryParse(idDI.Value, out baseId))
                       {
                           objectInfo.ParentId = baseId;
                       }
                   }
               }            
           }

            e.Tcs.SetResult(new DataObject("RTTIValueHolder", objectInfo.ToString()));
        }

        private void FillShapesPallete()
        {

            _objectCreationInfos = new Dictionary<string, PhysicsObjectCreationInfo>();

            try
            {
                XmlDocument shapesPallete = new XmlDocument();
                shapesPallete.Load("Data/ShapesPalette.objectspalette");

                XmlDocument physicsObjectsXML = new XmlDocument();
                physicsObjectsXML.Load("Data/PhysicsObjectsDefinition.xml");

                XmlNodeList physicsObjects = physicsObjectsXML.SelectNodes("/PhysicsObjects/PhysicsObject");
                XmlNode objPalleteNodes = shapesPallete.SelectSingleNode("/Objects");
                objPalleteNodes.RemoveAll();
                foreach (XmlNode physObj in physicsObjects)
                {
                    XmlNode objPallete = physObj.SelectSingleNode("ObjectsPaletteItem");

                    if (objPallete != null)
                    {
                        XmlNode importNode = shapesPallete.ImportNode(objPallete, true);
                        objPalleteNodes.AppendChild(importNode);

                        XmlNode physObjCI = physObj.SelectSingleNode("PhysicsObjectCreationInfo");

                        if (physObjCI != null)
                        {
                            EPhysicsBaseType baseType = EPhysicsBaseType.EPBT_Base;
                            var typeAtt = physObjCI.Attributes["Type"];
                            if ( ( typeAtt != null ) && EnumExtensions.FromString(out baseType, typeAtt.Value) )
                            {
                                PhysicsObjectCreationInfo item = new PhysicsObjectCreationInfo(baseType);

                                var geomAtt = physObjCI.Attributes["Geometry"];

                                if (geomAtt != null)
                                {
                                    EPhysicsShapeGeometryType geom;
                                    if( EnumExtensions.FromString(out geom, physObjCI.Attributes["Geometry"].Value) )
                                    {
                                        item.GeometryType = geom;
                                    }
                                }
                                _objectCreationInfos.Add(objPallete.Attributes["Name"].Value, item);
                            }                     
                        }
                    }
                }
                shapesPallete.Save("Data/ShapesPalette.objectspalette");     
            }
            catch (System.IO.IOException ex)
            {
                System.Console.WriteLine( ex.Message );
                return;
            }
        }

    }

}
